# -*- coding: utf-8 -*-
# created on 2017/1/16


from mathsolver.functions.base import *
from mathsolver.functions.base.base import new_latex
from sympy import cos, Tuple, sin, Abs
from mathsolver.functions.mathematica.mathematicaSolve import MathematicaSimplify
from mathsolver.functions.xiangliang.Vector_HuaJian import vector_huajian
from mathsolver.functions.xiangliang.Vector_Fundamental import vector_get_abs, vector_get_angles, vector_xiangs
from mathsolver.functions.process import ProcessExpression


def xl_search_multiple(known, poly):
    symbols = poly.free_symbols
    answer = []
    for name in known:
        if isinstance(name, Tuple):
            new_name = set(name)
            if new_name & symbols <= new_name:
                values = known[name]
                for value in values:
                    value = list(value)
                    for sym, v in zip(name, value):
                        v_index = value.index(v)
                        if isinstance(v, Interval):
                            value[v_index] = sym
                    symbol_value = dict([(sym, v) for sym, v in zip(name, value)])
                    answer.append(symbol_value)
        else:
            if name in symbols:
                values = known[name]
                if isinstance(values, list):
                    for value in values:
                        symbol_value = {name: value}
                        answer.append(symbol_value)
                elif isinstance(values, FiniteSet):
                    value = values.args[0]
                    symbol_value = {name: value}
                    answer.append(symbol_value)
                else:
                    value = values
                    if isinstance(value, Interval):
                        symbol_value = {name: name}
                        answer.append(symbol_value)
                    else:
                        symbol_value = {name: value}
                        answer.append(symbol_value)
    return answer


def xl_solutions_subs(solutions, target):
    answer = xl_search_multiple(solutions.sympify(), target)
    target_values = []
    for ans in answer:
        new_value = target
        new_value = new_value.subs(ans)
        new_value = new_value.expand().simplify()
        if len(str(new_value)) > 15:
            new_value = MathematicaSimplify().solver(BasePoly(new_value)).output[0].sympify()
        target_values.append(new_value)
    target_values = set(target_values)
    target_values = list(target_values)
    return target_values


class XLJiHeConditionEqTransform(BaseFunction):
    def solver(self, *args):
        eq = args[0].sympify()
        if len(eq) == 2:
            left, right = args[0].sympify()
            op = "="
        else:
            left, op, right = args[0].sympify()
        left = vector_huajian(left)
        left_abss = vector_get_abs(left)
        if left_abss:
            for left_Abs in left_abss:
                if self.search(str(left_Abs)):
                    left_abs_value = self.search(str(left_Abs))
                    left = left.subs({left_Abs: left_abs_value})
        left_c_angles = vector_get_angles(left)
        if left_c_angles:
            for left_CAngle in left_c_angles:
                if self.search(str(left_CAngle)):
                    left_c_angle_value = self.search(str(left_CAngle))
                    left = left.subs({left_CAngle: left_c_angle_value})
        left = left.expand().simplify()
        right = vector_huajian(right)
        right_abss = vector_get_abs(right)
        if right_abss:
            for right_Abs in right_abss:
                if self.search(str(right_Abs)):
                    right_abs_value = self.search(str(right_Abs))
                    right = right.subs({right_Abs: right_abs_value})
        right_c_angles = vector_get_angles(right)
        if right_c_angles:
            for right_CAngle in right_c_angles:
                if self.search(str(right_CAngle)):
                    right_c_angle_value = self.search(str(right_CAngle))
                    right = right.subs({right_CAngle: right_c_angle_value})
        right = right.expand().simplify()
        if isinstance(left, Pow):
            left **= 2
            left = left.expand().simplify()
            right **= 2
            right = right.expand().simplify()
        if len(eq) == 2:
            self.output.append(BaseEq([left, right]))
        else:
            self.output.append(BaseIneq([left, op, right]))
        return self


class XLJiHeConditionExprTransform(BaseFunction):
    def solver(self, *args):
        expr = args[0].sympify()
        expr = vector_huajian(expr)
        expr_abss = vector_get_abs(expr)
        if expr_abss:
            for expr_Abs in expr_abss:
                if self.search(str(expr_Abs)):
                    expr_abs_value = self.search(str(expr_Abs))
                    expr = expr.subs({expr_Abs: expr_abs_value})
        expr_c_angles = vector_get_angles(expr)
        if expr_c_angles:
            for expr_CAngle in expr_c_angles:
                if self.search(str(expr_CAngle)):
                    expr_c_angle_value = self.search(str(expr_CAngle))
                    expr = expr.subs({expr_CAngle: expr_c_angle_value})
        expr = expr.expand().simplify()
        self.output.append(BaseValue(expr))
        return self


class XLAxisConditionEqTransform(BaseFunction):
    def solver(self, *args):
        eq = args[0].sympify()
        eqs = []
        if isinstance(eq[1], (list, Tuple, tuple)):
            left = eq[0]
            right = eq[1]
            new_left = ProcessExpression(self.known).solver(BaseValue(str(left))).output[0].sympify()
            eqs.append([new_left[0], right[0]])
            eqs.append([new_left[1], right[1]])
            self.output.append(BaseEqs(eqs))
        else:
            if len(eq) == 3:
                left, op, right = eq
                expr = left - right
                new_expr = ProcessExpression(self.known).solver(BaseValue(str(expr))).output[0].sympify()
                eqs.append([new_expr, op, S.Zero])
            else:
                expr = eq[0] - eq[1]
                new_expr = ProcessExpression(self.known).solver(BaseValue(str(expr))).output[0].sympify()
                if isinstance(new_expr, tuple):
                    eqs.append([new_expr[0], S.Zero])
                    eqs.append([new_expr[1], S.Zero])
                else:
                    eqs.append([new_expr, S.Zero])
            self.output.append(BaseIneqs(eqs))
        return self


class XLJudgeAxis(BaseFunction):
    """
    判断是否可以用向量法解题
    """
    def solver(self, *args):
        targets = []
        for arg in args:
            targets.append(arg)
        veqs = self.known['Vequations']
        vectors = []
        for target in targets:
            xiangs = vector_xiangs(target)
            if xiangs:
                for xiang in xiangs:
                    vectors.append(xiang)
        for eq in veqs:
            if isinstance(eq[1], (list, tuple)):
                left = eq[0]
                xiangs = vector_xiangs(left)
                if xiangs:
                    for xiang in xiangs:
                        vectors.append(xiang)
            else:
                if len(eq) == 3:
                    expr = eq[0] - eq[2]
                else:
                    expr = eq[0] - eq[1]
                xiangs = vector_xiangs(expr)
                if xiangs:
                    for xiang in xiangs:
                        vectors.append(xiang)
        vectors = set(vectors)
        vectors = list(vectors)
        flag = []
        for vector in vectors:
            name = vector.args[0]
            name = str('Axis_') + str(name)
            if name in self.known:
                flag.append(1)
            else:
                flag.append(0)
        if sum(flag) > 0:
            answer = True
        else:
            answer = False
            for eq in veqs:
                if isinstance(eq[1], (list, tuple)):
                    answer = True
                    break
        self.output.append(BaseVariable(answer))
        return self


class XLXiangs(BaseFunction):
    def solver(self, *args):
        targets = []
        for arg in args:
            targets.append(arg)
        veqs = self.known['Vequations']
        vectors = []
        for target in targets:
            xiangs = vector_xiangs(target)
            if xiangs:
                for xiang in xiangs:
                    vectors.append(xiang)
        for eq in veqs:
            if isinstance(eq[1], (list, tuple)):
                left = eq[0]
                xiangs = vector_xiangs(left)
                if xiangs:
                    for xiang in xiangs:
                        vectors.append(xiang)
            else:
                if len(eq) == 3:
                    expr = eq[0] - eq[2]
                else:
                    expr = eq[0] - eq[1]
                xiangs = vector_xiangs(expr)
                if xiangs:
                    for xiang in xiangs:
                        vectors.append(xiang)
        vectors = set(vectors)
        vectors = list(vectors)
        self.output.append(BaseNumbers(vectors))
        return self


class XLTriangleConditionTransform(BaseFunction):
    def solver(self, *args):
        v_eqs = args[0]
        answer = {}
        for eq in v_eqs:
            expr = (eq[0] - eq[1]).expand().simplify()
            expr_symbols = list(expr.free_symbols)
            if len(expr_symbols) == 1:
                solutions = solve(expr, expr_symbols[0])
                answer[expr_symbols[0]] = solutions
        self.output.append(BaseSymbolValue(answer))
        return self


class VectorEqName(BaseFunction):
    def solver(self, *args):
        vectoreq = args[0].sympify()
        if isinstance(args[0], BaseVectorEq):
            name = vectoreq[0]
            self.output.append(BasePoly(name))
        return self


class AngleToCos(BaseFunction):
    """
    向量\\overrightarrow{a},\\overrightarrow{b}满足(\\overrightarrow{a}-\\overrightarrow{b})*(2\\overrightarrow{a}+\\overrightarrow{b})=-4,
    |\\overrightarrow {a} |=2,|\\overrightarrow{b}|=4,则\\overrightarrow{a} 与\\overrightarrow{b}夹角的余弦值等于.
    """
    def solver(self, *args):
        angles = args[0].sympify()
        cos_angles = []
        for angle in angles:
            val = cos(angle)
            val = val.expand().simplify()
            if len(str(val)) < 15:
                val = MathematicaSimplify().solver(BasePoly(val)).output[0].sympify()
            cos_angles.append(val)
        self.steps.append(["", "∴ %s" % " 或 ".join(["余弦值为%s" % (new_latex(v)) for v in cos_angles])])
        self.output.append(BaseNumbers(cos_angles))
        return self


class AngleToSin(BaseFunction):
    def solver(self, *args):
        angles = args[0].sympify()
        sin_angles = []
        for angle in angles:
            val = sin(angle)
            val = MathematicaSimplify().solver(BasePoly(val)).output[0].sympify()
            sin_angles.append(val)
        self.steps.append(["∴", " 或 ".join(["余弦值为%s" % (new_latex(v)) for v in sin_angles])])
        self.output.append(BaseNumbers(sin_angles))
        return self


class PolyToFunc(BaseFunction):
    def solver(self, *args):
        poly = args[0].sympify()
        symbols = poly.free_symbols
        symbol = list(symbols)[0]
        fx = "f(%s)" % symbol
        self.output.append(BaseEq([sympify(fx), poly]))
        return self


def xl_judge_sanjiao_vector(eqs):
    flag = []
    for eq in eqs:
        if isinstance(eq[1], (tuple, list)):
            expr = eq[0]
        else:
            if len(eq) == 2:
                expr = eq[0] - eq[1]
            else:
                expr = eq[0] - eq[2]
        p = r'vector\([A-Z][A-Z]\)'
        m = re.findall(p, str(expr))
        if m:
            flag.append(1)
        else:
            flag.append(0)
    if sum(flag) > 0:
        answer = True
    else:
        answer = False
    return answer


class XLSanJiaoEqsKnownUpdate(BaseFunction):
    def solver(self, *args):
        new_known = dict(self.known)
        judge_eqs = args[0]
        points = []
        for eq in judge_eqs:
            if isinstance(eq[1], (tuple, list)):
                expr = eq[0]
            else:
                expr = eq[0] - eq[1]
            p = r'vector\([A-Z][A-Z]\)'
            m = re.findall(p, str(expr))
            if m:
                for item in m:
                    new_item = sympify(item)
                    new_item_name = new_item.args[0]
                    if len(str(new_item_name)) == 2:
                        left_p, right_p = str(new_item_name)
                        points.append(left_p)
                        points.append(right_p)
        points = set(points)
        points = list(points)
        points_value = {}
        points_out = []
        for point in points:
            if point == str("O"):
                points_value[point] = (0, 0)
                points_out.append(BasePoint({"name": point, "value": [0, 0]}))
            else:
                lpoint_value = point + str("1")
                rpoint_value = point + str("2")
                points_value[point] = (sympify(lpoint_value), sympify(rpoint_value))
                points_out.append(BasePoint({"name": point, "value": [lpoint_value, rpoint_value]}))
        for eq in judge_eqs:
            if isinstance(eq[1], (tuple, list)):
                expr = eq[0]
            else:
                expr = eq[0] - eq[1]
            p = r'vector\([A-Z][A-Z]\)'
            m = re.findall(p, str(expr))
            if m:
                for item in m:
                    new_item = sympify(item)
                    new_item_name = new_item.args[0]
                    if len(str(new_item_name)) == 2:
                        left_p, right_p = str(new_item_name)
                        left_p_value = points_value[left_p]
                        right_p_value = points_value[right_p]
                        new_item_value = (right_p_value[0] - left_p_value[0], right_p_value[1] - left_p_value[1])
                        name = str('Axis_') + str(new_item_name)
                        new_known[name] = new_item_value
        self.output.append(new_known)
        self.steps.append(["", "设%s,则" % ",".join(["%s" % v.printing() for v in points_out])])
        return self


class VectorAxisKnownUpdate(BaseFunction):
    def solver(self, *args):
        known = dict(self.known)
        vectors_axis_names = args[0]
        vectors_names = []
        vectors_values = []
        for vectors_axis_name in vectors_axis_names:
            if vectors_axis_name not in known:
                name = vectors_axis_name[5:]
                vector_name = "vector" + "(" + name + ")"
                vector_name = sympify(vector_name)
                vectors_names.append(vector_name)
                new_name = sympify(name)
                if new_name == 0:
                    left = 0
                    right = 0
                else:
                    left = str(name) + '1'
                    left = sympify(left)
                    right = str(name) + '2'
                    right = sympify(right)
                vector_value = [left, right]
                vectors_values.append((left, right))
                known[vectors_axis_name] = vector_value
        if vectors_values:
            self.steps.append(["", "设%s, 则" % ",".join(["%s = %s" % (new_latex(a), new_latex(b)) for a, b
                                                        in zip(vectors_names, vectors_values)])])
        self.output.append(known)
        return self


class VectorAbsKnownUpdate(BaseFunction):
    def solver(self, *args):
        vectors = args[0]
        vectors_abs_names = []
        for vector in vectors:
            vector_name = vector.args[0]
            vector_abs_name = str('Abs_') + str(vector_name)
            vectors_abs_names.append(vector_abs_name)
        vectors_zuhe = list(itertools.combinations(vectors, 2))
        vectors_angle = []
        for item in vectors_zuhe:
            vector1, vector2 = item
            vector1_name = vector1.args[0]
            vector2_name = vector2.args[0]
            item_angle = str('CAngle_') + str(vector1_name) + str(vector2_name)
            vectors_angle.append(item_angle)
        tmp1 = ",".join(["%s = %s" % (new_latex(Abs(v1)), new_latex(v2)) for v1, v2 in zip(vectors, vectors_abs_names)])
        tmp2 = ",".join(["%s和%s的夹角为%s" % (new_latex(v3[0]), new_latex(v3[1]), new_latex(v4))
                        for v3, v4 in zip(vectors_zuhe, vectors_angle)])
        self.steps.append(["", "设%s, %s, 则" % (tmp1, tmp2)])
        return self


if __name__ == '__main__':
    pass
